﻿namespace WebPacker.Providers
{
	using System;
	using System.Collections.Generic;
	using System.IO;
	using System.Threading;
	using System.Web;
	using WebPacker.Compressors;
	using WebPacker.Configuration;
	using WebPacker.Helpers;
	using WebPacker.Packs;
	using WebPacker.Packs.Resources;
	using WebPacker.Packs.Watchers;

	public sealed class StaticPackProvider : IPackProvider, IDisposable
	{
		private IDictionary<PackKey, string> packUrlCache;
		private string source;
		private string sourcePhisicalPath;
		private string virtualPath;
		private bool disposed;
		private FileWatcher watcher;

		public StaticPackProvider()
		{
			packUrlCache = new Dictionary<PackKey, string>();
			watcher = new FileWatcher();
			watcher.Changed += OnSourceChange;
		}

		public string Url
		{
			get { return null; }
		}

		public string Source
		{
			get
			{
				return source;
			}

			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("Source");
				}

				source = value;
				sourcePhisicalPath = VirtualPathHelper.ToPhisicalPath(value);
				virtualPath = VirtualPathHelper.ToVirtualPath(Path.GetDirectoryName(sourcePhisicalPath));

				watcher.Clear();
				watcher.Add(new FileResource(sourcePhisicalPath));

				ReloadSource();
			}
		}

		public void Process(HttpContextBase context)
		{
			throw new WebPackerException("Invalid operation.");
		}

		public string GetUrl(ICompressor compressor, IPack pack)
		{
			string url;

			if (!packUrlCache.TryGetValue(new PackKey(pack.PackType, pack.Name), out url))
			{
				throw new WebPackerException(string.Format("Pack {0} isn't registered at \"{1}\".", pack, source));
			}

			return url;
		}

		public void Dispose()
		{
			if (!disposed)
			{
				watcher.Dispose();
				disposed = true;
			}
		}

		private void ReloadSource()
		{
			var newUrlCache = new Dictionary<PackKey, string>();
			var items = PackFileInfo.Deserialize(sourcePhisicalPath);

			foreach (var item in items)
			{
				var url = VirtualPathHelper.CombineUri(virtualPath, item.FileName);
				newUrlCache.Add(new PackKey(item.PackType, item.PackName), url);
			}

			Interlocked.Exchange(ref packUrlCache, newUrlCache);
		}

		private void OnSourceChange(object sender, ResourceChangedEventArgs e)
		{
			ReloadSource();
		}
	}
}